package sequentiell;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class Parser {

	String relationSymbol = "->";

	private ArrayList<Integer> nodes = new ArrayList<Integer>();
	private ArrayList<Integer> values = new ArrayList<Integer>();
	private ArrayList<String> relations = new ArrayList<String>();
	
	/**
	 * Initializates the parsing of the XML-graph
	 * @param filePath where XML-doc is saved
	 * @throws Exception if XML-doc has wrong format
	 */
	public Parser(String filePath) throws Exception {
		readGraph(filePath);
	}
	
	/**
	 * to get the nodes after parsing
	 * @return the list of nodes
	 */
	public ArrayList<Integer> getNodes(){
		return nodes;
	}
	
	/**
	 * to get the values after parsing
	 * @return the list of values
	 */
	public ArrayList<Integer> getValues(){
		return values;
	}
	
	/**
	 * to get the relations after parsing
	 * @return the list of relations
	 */
	public ArrayList<String> getRelations(){
		return relations;
	}
	
	/**
	 * the main parsing method
	 * @param filePath where the XML-doc is saved
	 * @throws Exception if XML-doc has wrong format or if DOMParser throws an exception
	 */
	private void readGraph(String filePath) throws Exception {
		
		//initializate 
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 
		DocumentBuilder builder = factory.newDocumentBuilder(); 
		Document document = builder.parse( new File(filePath) );
		
		NodeList list = document.getFirstChild().getChildNodes();
		Node node;
		for(int i=0;i<list.getLength();i++){
			node = list.item(i);
			switch(calcTag(node.getNodeName())){
			case NODE: readNode(node); break;
			case EDGE: readEdge(node); break;
			default: break;
			}
		}
	}
	
	/**
	 * read the id and value of a node
	 * @param node the node from the tree
	 * @throws IOException if XML-doc has wrong format
	 */
	private void readNode(Node node) throws IOException{
		NodeList childs = node.getChildNodes();
		Node idN = null,
			valueN = null,
			temp;
		for(int i=0;i<childs.getLength();i++){
			temp = childs.item(i);
			switch(calcTag(temp.getNodeName())){
			case ID: idN=temp; break;
			case CAPACITY: valueN=temp; break;
			default: break;
			}
		}
		
		if(idN==null || valueN==null)
			throw new IOException("Parser/readNode: XML-doc has wrong format!");
		
		int id = new Integer(idN.getTextContent().trim()).intValue(),
			value = new Integer(valueN.getTextContent().trim()).intValue();
		
		nodes.add(id);
		values.add(value);
	}
	
	/**
	 * read the source and destination of a relation
	 * @param node the node from the tree
	 * @throws IOException if XML-doc has wrong format
	 */
	private void readEdge(Node node) throws IOException{
		NodeList childs = node.getChildNodes();
		Node srcidN = null,
			dstidN = null,
			temp;
		for(int i=0;i<childs.getLength();i++){
			temp = childs.item(i);
			switch(calcTag(temp.getNodeName())){
			case SRCID: srcidN=temp; break;
			case DSTID: dstidN=temp; break;
			default: break;
			}
		}
		
		if(srcidN==null || dstidN==null)
			throw new IOException("Parser/readEdge: XML-doc has wrong format!");
		
		int srcid = new Integer(srcidN.getTextContent().trim()).intValue(),
			dstid = new Integer(dstidN.getTextContent().trim()).intValue();
		
		relations.add(srcid+relationSymbol+dstid);
	}
	
	/**
	 * for switch over the nodes from the tree
	 */
	private enum Tag {
		GRAPH, NODE, ID, CAPACITY, EDGE, SRCID, DSTID, TEXT, OTHER
	}
	
	/**
	 * calculate the tag for a specific string from a node
	 * @param line the string
	 * @return the tag
	 */
	private  Tag calcTag(String line){
		if (line.startsWith("graph"))
			return Tag.GRAPH;
		else if(line.startsWith("#text"))
			return Tag.TEXT;
		else if (line.startsWith("node"))
			return Tag.NODE;
		else if (line.startsWith("id"))
			return Tag.ID;
		else if (line.startsWith("capacity"))
			return Tag.CAPACITY;
		else if (line.startsWith("edge"))
			return Tag.EDGE;
		else if (line.startsWith("srcid"))
			return Tag.SRCID;
		else if (line.startsWith("dstid"))
			return Tag.DSTID;
		else return Tag.OTHER;
	}
	
}
